(***********************************************************************)
(*                                                                     *)
(*  Programowanie Funkcyjne                                            *)
(*  Wydział MiMUW                                                      *)
(*                                                                     *)
(*  Marcin Walas                                                       *)
(*  262460                                                             *)
(*                                                                     *)
(***********************************************************************)
(*

  Plik zawiera definicje typow i modulow uzywanych do zarzadzania
  logika gry w warcaby

*)

(* external *)
open OImages;;
open Printf;;

(* internal *)
open Gui;;
open Ai;;
open Checkers;;
open Breaktrough;;
open Common;;


type game_type = {
    mutable game:games_supported;
    mutable checkers_state : CheckersGame.state_type;
    mutable breaktrough_state : BreaktroughGame.state_type;
};;


type game_state_type = { 
    mutable game_instance : game_type;
    mutable human_moving : bool;
    mutable red_moving : bool;

    mutable alpha_beta_depth : int;
    mutable red : player_type;
    mutable white : player_type;
};;

let game_state = { 
    game_instance = { 
        game = Checkers; 
        checkers_state = CheckersGame.start_state ();
        breaktrough_state = BreaktroughGame.start_state ();
    };

    human_moving = true;
    red_moving = true;

    alpha_beta_depth = 2;

    red = {
        is_human = true;
    };

    white = {
        is_human = false;
    };

};;

let handlers = { 
    click_handler = (fun i j -> ()) ;
    new_game_handler = (fun () -> ());
    set_options_handler = (fun a b c d -> ());
    idle_handler = (fun () -> ());
};;


(* GAME DRIVER *)

module GameDriver = 
    (*
        Ten moduł ma funkcje, które się leniwie liczą, tworzy mi coś w kształcie
        sterownika gry, dzięki niemu można w ogóle przekazywać sterowanie do tych
        wszystkich modułów, które potrzebuję.
    *)
    struct


        let human_move () = 
            game_state.human_moving <- true;
            ()
            ;;



        let rec click_handler (x:int) (y:int) = 
            (* specjalne wartosci to -1 -1 dla wymuszenia ruchu AI *)
            eprintf "GAME NOTICE : GameDriver click_handler %d %d \n" x y;
            flush stderr;

            if (x < 0 || x >= 8 || y < 0 || y >= 8) && (x != -1) && (y != -1) then
                ()
            else
            (
             let return =
             (
                if game_state.human_moving then
                    (* tutaj już kod zależny od konkretnego typu gry się 
                        powinien wykonać *)
                (

                match game_state.game_instance.game with
                    (* EXTEND PLACE! *)
                    Checkers -> (let ret, state = (CheckersGame.click_handler game_state.game_instance.checkers_state (game_state.red_moving) x y) in
                                let _ = (CheckersGame.redraw state) in
                                    ((game_state.game_instance.checkers_state <- state); ret)) |

                    Breaktrough -> (let ret, state = (BreaktroughGame.click_handler game_state.game_instance.breaktrough_state (game_state.red_moving) x y) in
                                let _ = (BreaktroughGame.redraw state) in
                                    ((game_state.game_instance.breaktrough_state <- state); ret))


                ) else (

                    (* ruch wykonuje więc sztuczna inteligencja *)
                    if x = -1 && y = -1 then 
                    (

                        match game_state.game_instance.game with
                            
                            (* EXTEND PLACE! *)
                            Checkers -> 
                            (
                                eprintf "\n\nRECURSION STARTED\n";
                                flush stderr;
                                let move = (CheckersAI.make_move (CheckersExtended.get_pieces (game_state.game_instance.checkers_state)) (game_state.red_moving) (game_state.alpha_beta_depth)) in
                                eprintf "RECURSION ENDED\n";
                                flush stderr;

                                game_state.game_instance.checkers_state <- (CheckersGame.make_move game_state.game_instance.checkers_state move);
                                let _ = (CheckersGame.redraw game_state.game_instance.checkers_state) in
                                true
                            ) |
                            Breaktrough -> 
                            (
                                eprintf "\n\nRECURSION STARTED\n";
                                flush stderr;
                                let move = (BreaktroughAI.make_move (BreaktroughExtended.get_pieces (game_state.game_instance.breaktrough_state)) (game_state.red_moving) (game_state.alpha_beta_depth)) in
                                eprintf "RECURSION ENDED\n";
                                flush stderr;

                                game_state.game_instance.breaktrough_state <- (BreaktroughGame.make_move game_state.game_instance.breaktrough_state move);
                                let _ = (BreaktroughGame.redraw game_state.game_instance.breaktrough_state) in
                                true
                            )

                    ) else
                    false
                )
             ) in
                if return then (
                    (* człowiek wykonał ruch. Teraz AI jesli jest, albo drugi gracz *)
                    game_state.red_moving <- not game_state.red_moving;
                    if ((game_state.red_moving) && (game_state.red.is_human)) || ((not game_state.red_moving) && (game_state.white.is_human)) then 
                        human_move ()
                    else (
                        if (not game_state.red.is_human) && (not game_state.white.is_human) then (
                            game_state.human_moving <- false;
                            ()
                        ) else 
                        (ai_move ())
                    )

                )
            )
        and            

            ai_move () =
            game_state.human_moving <- false;
            click_handler (-1) (-1)
            ;;

        let idle_handler () = 
            if (not game_state.red.is_human) && (not game_state.white.is_human) then 
                (click_handler (-1) (-1))
            else
            ();;



        let is_human_the_first () =
            (* assuming that red starts the game *)
            game_state.red.is_human
            ;;

        let restart () =
            game_state.human_moving <- is_human_the_first ();
            match game_state.game_instance.game with 
                (* EXTEND PLACE! *)
                Checkers -> (
                             game_state.game_instance.checkers_state <- CheckersGame.start_state ();
                             CheckersGame.redraw game_state.game_instance.checkers_state;
            if not game_state.human_moving then
            (
                eprintf "Calling click_handler from restart\n";
                flush stderr;
                (click_handler (-1) (-1))

            )
            else ()

                            ) |
                Breaktrough -> (
                             game_state.game_instance.breaktrough_state <- BreaktroughGame.start_state ();
                             BreaktroughGame.redraw game_state.game_instance.breaktrough_state;
            if not game_state.human_moving then
            (
                eprintf "Calling click_handler from restart\n";
                flush stderr;
                (click_handler (-1) (-1))

            )
            else ()

                            )
            ;
            ;;

        let rec set_options (game : games_supported) (red : player_type) (white : player_type) (alpha_beta_depth:int) =
            eprintf "GAME NOTICE set_options called %B %B\n" red.is_human white.is_human;
            flush stderr;

            game_state.red <- red;
            game_state.white <- white;
            game_state.alpha_beta_depth <- alpha_beta_depth;
            startup game ()

        and
        startup (game : games_supported) () =
            (*
                Resetuje grę i ustawia na konkretny typ gry 
            *)
            eprintf "GAME NOTICE : GameDriver startup\n";
            flush stderr;

            handlers.click_handler <- click_handler;
            handlers.new_game_handler <- restart;
            handlers.set_options_handler <- set_options;
            handlers.idle_handler <- idle_handler;


            game_state.game_instance.game <- game;
            restart ();;

    end;;

(* module *)

let main () =
    eprintf "MAIN at main.ml started\n";
    flush stderr;

    let _ = GameDriver.startup Checkers () in
       
    Gui.main handlers ()
    ;;

let _ = main ();;


let _ = eprintf "KONCZYMY WYKONANIE PROGRAMU \n";;
let _ = flush stderr;;

